chore(git): sync with main - #31331
Merged
Merged
Conversation
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.1` → `v4.37.3` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.3`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.3) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.2...v4.37.3) No user facing changes. ### [`v4.37.2`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.2) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.1...v4.37.2) - The new address format for the `config-file` input that was introduced in CodeQL Action 4.37.0 is now enabled by default. In addition to the format described there, the `remote=` prefix can now be used to explicitly indicate that the input refers to a remote file. All previous input formats continue to be accepted as well. [#​4023](https://redirect.github.com/github/codeql-action/pull/4023) - The CodeQL Action can now make use of [configured private registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) in Default Setup to retrieve CodeQL configuration files from remote repositories that require authentication. This will allow customers to store their CodeQL configuration in a single repository that can then be referenced by Default Setup workflows in other repositories. We expect to roll this and other, related changes out to everyone in July. [#​4007](https://redirect.github.com/github/codeql-action/pull/4007) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Issue number: internal --------- ## What is the current behavior? When a sheet modal uses `handleBehavior="cycle"`, the host element is focusable (`tabIndex=0`) and `onModalFocus` redirects focus to the drag handle whenever the host is focused. `present()` moves focus to the `.modal-wrapper` (the `role="dialog"` element) inside the shadow DOM, but that focus event is retargeted to the host, so `onModalFocus` sees `ev.target === el` and treats it as a direct host focus. It then bounces focus onto the handle. This is latent on the default `handleBehavior="none"` (the host isn't focusable, so the redirect never runs), but reproduces on any sheet modal that opts into `cycle`. ## What is the new behavior? `onModalFocus` now redirects to the handle only when the host itself was focused directly, detected by `el.shadowRoot?.activeElement` being `null`. When `present()` focuses the dialog wrapper, `activeElement` is the wrapper (not null), so the redirect is skipped and the dialog keeps focus. Tabbing into the modal from outside still lands on the handle, since the host is the focused element in that case. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information Related to the dialog focus work in #31260 . That change is correct under the default `handleBehavior`, but the `cycle` path was not covered until now. Adds an e2e test to `utils/test/overlays/overlays.e2e.ts` that presents a sheet modal with `handle-behavior="cycle"` and asserts focus stays on the wrapper. The same fix ships on the major-9.0 sync (#31290), where `cycle` is the default and this bug is hit on every sheet modal. Preview (sheet modal test page): - iOS: https://ionic-framework-git-fix-modal-focus-cycle-ionic1.vercel.app/src/components/modal/test/sheet?ionic:mode=ios - MD: https://ionic-framework-git-fix-modal-focus-cycle-ionic1.vercel.app/src/components/modal/test/sheet?ionic:mode=md
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [chalk](https://redirect.github.com/chalk/chalk) | [`^5.3.0` → `^6.0.0`](https://renovatebot.com/diffs/npm/chalk/5.6.2/6.0.0) |  |  | --- ### Release Notes <details> <summary>chalk/chalk (chalk)</summary> ### [`v6.0.0`](https://redirect.github.com/chalk/chalk/compare/v5.6.2...661317e6f91fe7c90306c2c48ea9354562ee9146) [Compare Source](https://redirect.github.com/chalk/chalk/compare/v5.6.2...v6.0.0) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…when focused (#31276) Issue number: resolves #30401 --------- ## What is the current behavior? The floating label and placeholder on `ion-select` overlap when focused without a value ## What is the new behavior? The placeholder is not shown when a floating label select is focused, as that space is taken up by the label ## Does this introduce a breaking change? - [ ] Yes - [x] No
Issue number: internal --------- ## What is the current behavior? The shared `dragElementBy` Playwright helper (`core/src/utils/test/playwright/drag-element.ts`, used by every gesture e2e test) unconditionally runs `await page.evaluate(() => window.getSelection()?.removeAllRanges())` between `mouse.down()` and the drag movement. That line was added in #31260 to clear a Firefox-only text selection, but the extra `page.evaluate()` is an awaited round-trip that injects variable latency into the gesture path for all browsers. On WebKit that latency messes up the gesture's timing-derived `velocityX`, so the `item-sliding` safe-area screenshot tests in md mode settle a few pixels off and flake randomly. Since it lives on main, the flake has propagated to every other branch (next and major-9.0) and causes random test failures in PRs and nightlies. ## What is the new behavior? The selection clear now only runs on Firefox, which is the only engine that needs it (the existing comment already scoped the problem to Firefox). Chromium and WebKit skip the extra round-trip and get the same drag timing they had before #31260, so the item settles deterministically and the flake goes away. This matches the `browserType().name() === 'webkit'` gate already used elsewhere in the same file. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Regression was introduced by #31260 (the `removeAllRanges` line, not the modal a11y change itself). Verified by running in docker locally several times.
Issue number: resolves #31296 --------- ## What is the current behavior? `StackController.destroy()` sets `this.containerEl = undefined!`, but a transition that is still queued behind `wait()` can resolve after the `ion-router-outlet` was destroyed (interrupted / re-entrant / cancelled navigation during fast back-navigation). `transition()` then dereferences the `undefined` element at `if ((containerEl as any).commit)` and throws: ``` TypeError: undefined is not an object (evaluating 'containerEl.commit') at transition ``` Observed at production scale in an Ionic Angular + Capacitor app (several hundred RUM crash events per week from a single build, concentrated on rapid back-navigation between nested outlets). ## What is the new behavior? - `transition()` null-checks `containerEl` (optional chaining) before probing for `commit`. - A transition resolving after its outlet was destroyed now takes the method's existing fallback path and resolves `false`, instead of throwing an unhandled `TypeError`. - No behavior change for live outlets. Regarding tests: there is no existing unit harness for `StackController` (only the e2e test apps), and the defect is a timing race between a queued transition and outlet destruction, which is impractical to reproduce deterministically in e2e. The change is a defensive null-check on a field that `destroy()` explicitly sets to `undefined` (with a lint-suppressed non-null assertion). We have run this exact guard in production via patch-package: the crash class disappears with no observed regressions. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information The unguarded dereference is present in v8.8.13 through latest stable 8.8.15 and `8.8.16-nightly.20260724`. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | Type | Update | |---|---|---|---|---|---| | [@playwright/test](https://playwright.dev) ([source](https://redirect.github.com/microsoft/playwright)) | [`^1.61.1` → `^1.62.0`](https://renovatebot.com/diffs/npm/@playwright%2ftest/1.61.1/1.62.0) |  |  | devDependencies | minor | | mcr.microsoft.com/playwright | `v1.61.1` → `v1.62.0` |  |  | final | minor | | [playwright-core](https://playwright.dev) ([source](https://redirect.github.com/microsoft/playwright)) | [`^1.61.1` → `^1.62.0`](https://renovatebot.com/diffs/npm/playwright-core/1.61.1/1.62.0) |  |  | devDependencies | minor | --- ### Release Notes <details> <summary>microsoft/playwright (@​playwright/test)</summary> ### [`v1.62.0`](https://redirect.github.com/microsoft/playwright/releases/tag/v1.62.0) [Compare Source](https://redirect.github.com/microsoft/playwright/compare/v1.61.1...v1.62.0) ##### 🧱 New component testing model [Component testing](https://playwright.dev/docs/test-components) moves to a **stories and galleries** model. A **story** wraps your component in one specific scenario — hard-coded props, mock data, providers — and a **gallery** page that you serve renders stories on demand. The new [fixtures.mount()](https://playwright.dev/docs/api/class-fixtures#fixtures-mount) fixture navigates to the gallery, mounts a story by id, and returns a [Locator](https://playwright.dev/docs/api/class-locator) scoped to the story's root element: ```js test('click should expand', async ({ mount }) => { const component = await mount('components/Expandable/Stateful'); await component.getByRole('button').click(); await expect(component.getByTestId('expanded')).toHaveValue('true'); }); ``` Pass a story type as a template argument to type-check its props, and use `update(props)` / `unmount()` on the returned locator to re-render or tear down within a test. ##### 🛑 Cancel operations with AbortSignal Most operations and web-first assertions now accept a `signal` option that takes an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal), letting you cancel long-running actions, navigations, waits, and assertions: ```js const controller = new AbortController(); setTimeout(() => controller.abort(), 1000); await page.getByRole('button', { name: 'Submit' }).click({ signal: controller.signal }); await expect(page.getByText('Done')).toBeVisible({ signal: controller.signal }); ``` Providing a signal does not disable the default timeout; pass `timeout: 0` to disable it. ##### 🖼️ WebP screenshots [expect(page).toHaveScreenshot()](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) and [expect(locator).toHaveScreenshot()](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-have-screenshot-1) can now store snapshots in the WebP format — just give the snapshot a `.webp` name: ```js // Visual comparisons store the golden snapshot as lossless WebP. await expect(page).toHaveScreenshot('homepage.webp'); // Standalone screenshots can trade quality for size with lossy WebP. await page.screenshot({ path: 'homepage.webp', quality: 50 }); ``` [page.screenshot()](https://playwright.dev/docs/api/class-page#page-screenshot) and [locator.screenshot()](https://playwright.dev/docs/api/class-locator#locator-screenshot) also accept `webp` as a `type`, where quality `100` (the default) is lossless and lower values use lossy compression. ##### 🧩 Custom test filtering with Reporter.preprocess() New [reporter.preprocess()](https://playwright.dev/docs/api/class-reporter#reporter-preprocess) hook runs after the configuration is resolved and before [reporter.onBegin()](https://playwright.dev/docs/api/class-reporter#reporter-on-begin), letting a reporter mark individual tests as skipped, excluded, fixed, or failing through a [TestRun](https://playwright.dev/docs/api/class-testrun) object: ```js class MyReporter { async preprocess({ config, suite, testRun }) { for (const test of suite.allTests()) { if (shouldSkip(test)) testRun.skip(test); } } } ``` ##### 🔁 Isolated retries New [testConfig.retryStrategy](https://playwright.dev/docs/api/class-testconfig#test-config-retry-strategy) controls when failed tests are retried. The default `'immediate'` retries as soon as a worker is free; `'isolated'` runs all retries at the end, one by one in a single worker, to minimize interference with the rest of the suite: ```js // playwright.config.ts export default defineConfig({ retries: 2, retryStrategy: 'isolated', }); ``` ##### New APIs ##### Browser and Context - New option [`credentials`](https://playwright.dev/docs/api/class-browsercontext#browser-context-storage-state-option-credentials) includes the context's virtual WebAuthn [Credentials](https://playwright.dev/docs/api/class-credentials) (passkeys) in the storage state, so they can be persisted and re-seeded into later contexts. ##### Actions - New `scroll` option (`"auto"` | `"none"`) on actions to opt out of Playwright's automatic scroll-into-view. ##### Network - New [apiResponse.timing()](https://playwright.dev/docs/api/class-apiresponse#api-response-timing) returns resource timing information for an API response. ##### Evaluation - New [locator.waitForFunction()](https://playwright.dev/docs/api/class-locator#locator-wait-for-function) waits until a function — called with the matching element — returns a truthy value. - [page.evaluate()](https://playwright.dev/docs/api/class-page#page-evaluate) and related methods now accept functions as evaluate arguments. - [page.addInitScript()](https://playwright.dev/docs/api/class-page#page-add-init-script) / [browserContext.addInitScript()](https://playwright.dev/docs/api/class-browsercontext#browser-context-add-init-script) now accept functions as init-script arguments. ##### Command line & MCP - Playwright now bundles the [Playwright MCP](https://playwright.dev/docs/getting-started-mcp) server and [`playwright-cli`](https://playwright.dev/docs/getting-started-cli), runnable via `npx playwright mcp` and `npx playwright cli`. ##### Reporters - The HTML report's **Merge files** grouping — previously only a UI toggle — can now be enabled from the config with the new `mergeFiles` reporter option: ```js // playwright.config.ts export default defineConfig({ reporter: [['html', { mergeFiles: true }]], }); ``` ##### Announcements -⚠️ Debian 11 is not supported anymore. ##### Browser Versions - Chromium 151.0.7922.34 - Mozilla Firefox 153.0 - WebKit 26.5 This version was also tested against the following stable channels: - Google Chrome 151 - Microsoft Edge 151 </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: ionitron <hi@ionicframework.com>
v8.8.16
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.3` → `v4.37.4` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.4`](https://redirect.github.com/github/codeql-action/compare/v4.37.3...v4.37.4) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.3...v4.37.4) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Updates Docker instructions to include the required Virtual Machine settings for Rancher Desktop. Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/labeler](https://redirect.github.com/actions/labeler) | action | major | `v6.2.0` → `v7.0.0` | --- ### Release Notes <details> <summary>actions/labeler (actions/labeler)</summary> ### [`v7.0.0`](https://redirect.github.com/actions/labeler/compare/v6.2.0...v7.0.0) [Compare Source](https://redirect.github.com/actions/labeler/compare/v7.0.0...v7.0.0) ### [`v7`](https://redirect.github.com/actions/labeler/compare/v6.2.0...v7.0.0) [Compare Source](https://redirect.github.com/actions/labeler/compare/v6.2.0...v7.0.0) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQ0LjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/checkout](https://redirect.github.com/actions/checkout) | action | patch | `v7.0.0` → `v7.0.1` | --- ### Release Notes <details> <summary>actions/checkout (actions/checkout)</summary> ### [`v7.0.1`](https://redirect.github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v701) [Compare Source](https://redirect.github.com/actions/checkout/compare/v7.0.0...v7.0.1) - Bump github/codeql-action from 3 to 4 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2475](https://redirect.github.com/actions/checkout/pull/2475) - Bump actions/setup-node from 4 to 6 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2477](https://redirect.github.com/actions/checkout/pull/2477) - Bump docker/build-push-action from 6.5.0 to 7.2.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2478](https://redirect.github.com/actions/checkout/pull/2478) - Bump docker/login-action from 3.3.0 to 4.2.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2479](https://redirect.github.com/actions/checkout/pull/2479) - Bump actions/checkout from 6 to 7 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2488](https://redirect.github.com/actions/checkout/pull/2488) - Bump actions/upload-artifact from 4 to 7 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2476](https://redirect.github.com/actions/checkout/pull/2476) - eslint 9 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2474](https://redirect.github.com/actions/checkout/pull/2474) - Bump the minor-actions-dependencies group with 2 updates by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2499](https://redirect.github.com/actions/checkout/pull/2499) - skip running unsafe pr check if input is default by [@​aiqiaoy](https://redirect.github.com/aiqiaoy) in [#​2518](https://redirect.github.com/actions/checkout/pull/2518) - trim only ascii whitespace for branch by [@​aiqiaoy](https://redirect.github.com/aiqiaoy) in [#​2521](https://redirect.github.com/actions/checkout/pull/2521) - escape values passed to --unset by [@​aiqiaoy](https://redirect.github.com/aiqiaoy) in [#​2530](https://redirect.github.com/actions/checkout/pull/2530) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQ0LjMuMiIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | Type | Update | |---|---|---|---|---|---| | [@playwright/test](https://playwright.dev) ([source](https://redirect.github.com/microsoft/playwright)) | [`^1.62.0` → `^1.62.1`](https://renovatebot.com/diffs/npm/@playwright%2ftest/1.62.0/1.62.1) |  |  | devDependencies | patch | | mcr.microsoft.com/playwright | `v1.62.0` → `v1.62.1` |  |  | final | patch | | [playwright-core](https://playwright.dev) ([source](https://redirect.github.com/microsoft/playwright)) | [`^1.62.0` → `^1.62.1`](https://renovatebot.com/diffs/npm/playwright-core/1.62.0/1.62.1) |  |  | devDependencies | patch | --- ### Release Notes <details> <summary>microsoft/playwright (@​playwright/test)</summary> ### [`v1.62.1`](https://redirect.github.com/microsoft/playwright/compare/v1.62.0...26a9e470a7b3c7822084b09fb7f13902c5f37b51) [Compare Source](https://redirect.github.com/microsoft/playwright/compare/v1.62.0...v1.62.1) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…1295) Issue number: internal --------- ## What is the current behavior? Currently, `ion-checkbox` and `ion-toggle` never show a keyboard focus indicator. `ion-checkbox` doesn't set the `ion-focusable` class and has no focus styles in the `ios` or `md` themes, so it can't receive the `ion-focused` class or render a ring. `ion-toggle`'s only focus rule (`:host(.ion-focused) input`) targets the native `input`, which is `display: none`, so it never renders. Separately, `ion-checkbox`, `ion-radio`, and `ion-toggle` show no focus indicator inside an `ion-item` that holds more than one input. `ion-checkbox` and `ion-radio` disable their own indicator in an item on the assumption the item draws one, but a multi-input item has no cover to highlight, so nothing is focused. ## What is the new behavior? `ion-checkbox` now sets `ion-focusable` when it isn't deferring to an item, with matching `ios` and `md` focus styles, so a standalone checkbox shows the same indicator `ion-radio` already did. Both `ion-checkbox` and `ion-radio` also become focusable inside a multi-input item, detected through the item's `item-multiple-inputs` class, so each control shows its own indicator when the item can't. `ion-toggle` always shows its own indicator. Unlike checkbox and radio, it's excluded from the item's input cover, so an item never highlights on its behalf, in or out of a multi-input item. Its dead `input` focus rule is replaced with a ring on the visible track in both themes. ## Does this introduce a breaking change? - [ ] Yes - [X] No ## Other information Preview checkbox: - iOS: https://ionic-framework-git-fw-7585-fw-7586-ionic1.vercel.app/src/components/checkbox/test/basic?ionic:mode=ios - MD: https://ionic-framework-git-fw-7585-fw-7586-ionic1.vercel.app/src/components/checkbox/test/basic?ionic:mode=md Preview toggle: - https://ionic-framework-git-fw-7585-fw-7586-ionic1.vercel.app/src/components/toggle/test/basic?ionic:mode=ios - https://ionic-framework-git-fw-7585-fw-7586-ionic1.vercel.app/src/components/toggle/test/basic?ionic:mode=md Preview radio: - https://ionic-framework-git-fw-7585-fw-7586-ionic1.vercel.app/src/components/radio/test/basic?ionic:mode=ios - https://ionic-framework-git-fw-7585-fw-7586-ionic1.vercel.app/src/components/radio/test/basic?ionic:mode=md --------- Co-authored-by: ionitron <hi@ionicframework.com>
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@capacitor/core](https://capacitorjs.com) ([source](https://redirect.github.com/ionic-team/capacitor)) | [`8.4.2` → `8.5.0`](https://renovatebot.com/diffs/npm/@capacitor%2fcore/8.4.2/8.5.0) |  |  | --- ### Release Notes <details> <summary>ionic-team/capacitor (@​capacitor/core)</summary> ### [`v8.5.0`](https://redirect.github.com/ionic-team/capacitor/blob/HEAD/CHANGELOG.md#850-2026-07-31) [Compare Source](https://redirect.github.com/ionic-team/capacitor/compare/8.4.2...8.5.0) ##### Bug Fixes - **cli:** support TypeScript 7 when loading capacitor.config.ts ([#​8534](https://redirect.github.com/ionic-team/capacitor/issues/8534)) ([4c1c870](https://redirect.github.com/ionic-team/capacitor/commit/4c1c8709413b9c19b008c99122ca330cc3c90e6f)) ##### Features - **cli:** add migrator functionality for adopting UIScene ([#​8544](https://redirect.github.com/ionic-team/capacitor/issues/8544)) ([984fa85](https://redirect.github.com/ionic-team/capacitor/commit/984fa85ba0adab0aacf895aed6323bf4b503dccb)) - **ios:** UIScene Support ([#​8536](https://redirect.github.com/ionic-team/capacitor/issues/8536)) ([3fa04a3](https://redirect.github.com/ionic-team/capacitor/commit/3fa04a357c92af34cd6fccb8124791963804a9dc)) #### [8.4.2](https://redirect.github.com/ionic-team/capacitor/compare/8.4.1...8.4.2) (2026-07-14) ##### Bug Fixes - **android:** explicitly grant URI permissions for image capture intent ([#​8526](https://redirect.github.com/ionic-team/capacitor/issues/8526)) ([6f2d328](https://redirect.github.com/ionic-team/capacitor/commit/6f2d3283897a375d09ca9ec8784a9f0d65f0a530)) #### [8.4.1](https://redirect.github.com/ionic-team/capacitor/compare/8.4.0...8.4.1) (2026-06-19) ##### Bug Fixes - **cli:** make SPM dependency patch work on prereleases ([#​8508](https://redirect.github.com/ionic-team/capacitor/issues/8508)) ([6048e90](https://redirect.github.com/ionic-team/capacitor/commit/6048e90171afa0229a3c25b52a23c377c6bb804c)) - **cli:** patch Capacitor SPM dependency version in plugins ([#​8492](https://redirect.github.com/ionic-team/capacitor/issues/8492)) ([28bb2c6](https://redirect.github.com/ionic-team/capacitor/commit/28bb2c687069dfdd6aa7abc866004a1c6388d103)) </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "every weekday before 11am" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Issue number: resolves #31315 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> When an `ion-refresher`'s host page is unmounted while the native refresher is still being set up, Ionic throws an uncaught `TypeError` from the gesture utility: ``` TypeError: Cannot read properties of undefined (reading '__zone_symbol__addEventListener') at addEventListener (core/src/utils/gesture/listener.ts:21) at Object.enable (core/src/utils/gesture/index.ts) at Refresher.disabledChanged (core/src/components/refresher/refresher.tsx:125) at Refresher.setupMDNativeRefresher (core/src/components/refresher/refresher.tsx:372) ``` `setupMDNativeRefresher()` and `setupiOSNativeRefresher()` both do: ```ts this.gesture = (await import('../../utils/gesture')).createGesture({ el: this.scrollEl!, ... }); ``` The dynamic import yields to the event loop. If the refresher is disconnected while it resolves, `disconnectedCallback()` (line 547-549) has already run `this.scrollEl = undefined`, so `createGesture` receives `el: undefined`, and the subsequent `disabledChanged()` → `gesture.enable(true)` calls `addEventListener(undefined, ...)`, which throws. Because this happens inside an async method that nothing awaits, it surfaces as an **unhandled promise rejection** — it cannot be caught by a framework error boundary; this crashes my app in playwright sometimes when components are mounted very quickly. The `!` non-null assertions on `this.scrollEl` are what hide this from TypeScript. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> If the refresher is disconnected while the gesture module is being imported, setup aborts quietly. No gesture is created, and no error is thrown. ## Does this introduce a breaking change? - [ ] Yes - [ X] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> --------- Co-authored-by: Shane <shane@shanessite.net>
…ken contributing link (#31250) Issue number: resolves #31251 --------- ## What is the current behavior? While working on e2e tests in the angular directory, I encountered a few documentation issues that made the local development workflow more difficult to follow. - The **"See Ionic's E2E testing guide"** link in `CONTRIBUTING.md` resolves to a 404 when viewed from GitHub's **Contributing** tab because the relative path is not resolved correctly. - Broken link: https://github.com/ionic-team/ionic-framework/blob/core/src/utils/test/playwright/docs/README.md - Intended destination: https://github.com/ionic-team/ionic-framework/blob/main/core/src/utils/test/playwright/docs/README.md - The Angular testing guide (`docs/angular/testing.md`) omits several steps that are necessary to successfully test local framework changes, including: - Removing existing `npm link` relationships before starting a new sync cycle. - Building `packages/angular-server`. - Installing Playwright browser dependencies before running Playwright tests for the first time. These omissions made it difficult to reproduce and validate additions to Angular tests I was adding as part of a separate PR. ## What is the new behavior? This PR does the following: - Fixes the broken link to the Ionic E2E testing guide in `CONTRIBUTING.md` by using a repository-root-relative path. - Updating `docs/angular/testing.md` to document the complete workflow for syncing local Angular framework changes. - Documents that `packages/angular-server` should be built as part of the local testing workflow. - Documents that contributors should remove previous `npm link` relationships before beginning a new sync cycle. - Clarifies the recommended workflow for syncing local package changes. - Documents the Playwright browser installation step required before running Playwright tests for the first time. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information --------- Co-authored-by: Maria Hutt <thetaPC@users.noreply.github.com>
Issue number: resolves #31152 ## What is the current behavior? In `IonRouter.handleHistoryChange`, the URL-change guard compares mismatched operands: ```ts const leavingUrl = leavingLocationInfo.pathname + leavingLocationInfo.search; if (leavingUrl !== location.pathname) { ... } ``` The left side includes `search`, the right side does not. For any route with a non-empty query string, the comparison is **always** unequal, so the transition block runs on every history event — including no-op popstates over same-URL entries pushed via `window.history.pushState`. Concretely: when a same-URL history entry on a search-bearing route is popped, `action === 'POP'` is processed and the IRO transitions to `currentRoute.pushedByRoute`. The browser URL doesn't change but the rendered view does — the user gets silently teleported to a different page in the stack. Minimal repro: on any search-bearing route, run in the console: ```js window.history.pushState({}, '', window.location.href); window.history.back(); ``` The current behavior swaps the rendered page to the previous entry in `locationHistory` while the URL stays put. Expected: no visible change. Full repro and analysis in #31152. This is also the root cause behind the symptom reported in #25534 (framed there as a transition-rerender flash). ## What is the new behavior? The right side of the comparison now also includes `search`, so the block only runs when the URL actually changed: ```ts const leavingUrl = leavingLocationInfo.pathname + leavingLocationInfo.search; const currentUrl = location.pathname + (location.search || ''); if (leavingUrl !== currentUrl) { ... } ``` Behavior matrix: - Search-only navigations (e.g. `routerPush(samePath + newSearch)`): **unchanged** — pathname matches but search differs, block still runs. - Pathname changes: **unchanged** — pathnames differ, block still runs. - No-op popstates on search-bearing routes: **fixed** — pathname + search both match, block correctly skipped. A new Cypress regression test is included (`packages/react-router/test/base/tests/e2e/specs/routing.cy.js`) that pushes a same-URL state on a search-bearing route, calls `history.back()`, and asserts the page does not teleport. ## Does this introduce a breaking change? - [ ] Yes - [x] No The comparison becomes stricter (skips the block in more cases than before), but only for the cases where the URL didn't actually change. All cases where the URL *did* change are still routed through the existing transition logic unchanged. ## Other information Happy to iterate on the fix shape if there's a preferred alternative — e.g. gating behind a flag for backward compat, or restructuring the guard differently. The one-line change above is the smallest possible fix that keeps existing behavior for every "real URL change" case. --------- Co-authored-by: ShaneK <shane@shanessite.net>
…ty (#31249) ## Summary Fixes #18550 — `ion-fab-button` with `type="submit"` does not submit its parent form. **Root cause:** `ion-fab-button` uses Shadow DOM, so its internal `<button>` element is not part of the form-associated elements in the light DOM. Clicking it (or pressing Enter in a text field) never triggers the form's `submit` event. **Fix:** Port the hidden-button pattern already used by `ion-button`: - On render (when `type !== 'button'`), inject a hidden `<button>` into the associated form in the light DOM. - On click, call `ev.preventDefault()` to stop the shadow button from acting, then `.click()` the hidden button — which is a proper form participant and triggers submission. - Add a `form` prop (`string | HTMLFormElement`) so the button can target a form outside its DOM subtree (same API as `ion-button`). - Keep the `disabled` watcher in sync with the hidden button so a disabled fab-button cannot submit. ## Changes - `core/src/components/fab-button/fab-button.tsx` — core fix - `core/src/components/fab-button/test/form/fab-button.e2e.ts` — Playwright e2e tests (closest form, form by id, form by reference, Enter key, disabled, reset) - `core/src/components/fab-button/test/form/fab-button.spec.ts` — unit test asserting the hidden button is not duplicated on re-renders - `core/src/components/fab-button/test/form/index.html` — visual test page ## Test plan - [ ] `npm run test.spec` passes (unit test for hidden-button dedup) - [ ] `npm run test.e2e` passes for `fab-button/test/form/fab-button.e2e.ts` - [ ] Manual: `ion-fab-button type="submit"` inside a `<form>` submits on click - [ ] Manual: pressing Enter in a form input triggers submit - [ ] Manual: `ion-fab-button type="reset"` resets form fields - [ ] Manual: disabled fab-button does not submit - [ ] Manual: `form="id"` targets an external form --------- Co-authored-by: ShaneK <shane@shanessite.net>
Issue number: internal
---------
## What is the current behavior?
Currently, `prepareLazyLoaded` in `ion-tab` sets `loaded = true` before
it attempts the attach, and the `try/catch` wrapped around
`attachComponent` is synchronous while `attachComponent` itself is
`async`. So when the first attach rejects, the rejection skips the
`catch` entirely and `loaded` is already `true`, which means the `if
(!this.loaded && ...)` guard blocks every later attempt. The tab renders
as an empty page for the rest of the session, even if whatever caused
the failure is fixed.
`ion-tabs` activates a tab by setting `active` rather than by awaiting
the tab's `setActive()`, so the failure goes through the
`@Watch('active')` path. That call isn't awaited, so on rejection the
error surfaces as an unhandled promise rejection and `printIonError`
never runs. `select()` resolves successfully while the tab is blank, so
there's no signal to the caller either.
## What is the new behavior?
With this change, `prepareLazyLoaded` caches the in-flight attach
promise instead of flipping a boolean up front. Concurrent activations
still share a single attempt, which is what the old `loaded = true`
ordering was providing, but the cache is only cleared when the attach
rejects, so the next activation retries. The unawaited call in the
`active` watcher now has a `.catch` that routes the error to
`printIonError`, which is what the unreachable `catch` block was there
for.
`setActive()` still rejects on a failed attach and still leaves `active`
as `false`, so that part is unchanged.
## Does this introduce a breaking change?
- [ ] Yes
- [X] No
## Other information
There's no stock test page that reproduces the failure, since it needs a
delegate that rejects, but the tabs pages confirm normal lazy loading
still works:
- [Tabs:
Basic](https://ionic-framework-git-fw-7296-ionic1.vercel.app/src/components/tabs/test/basic)
v8.8.17
# Conflicts: # core/package-lock.json # core/package.json # core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-md-ltr-Mobile-Chrome-linux.png # core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-md-ltr-Mobile-Chrome-linux.png # core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-Mobile-Chrome-linux.png # core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-dark-Mobile-Chrome-linux.png # core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-Mobile-Chrome-linux.png # core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-dark-Mobile-Chrome-linux.png # core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-ltr-Mobile-Chrome-linux.png # core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-rtl-Mobile-Chrome-linux.png # core/src/components/checkbox/checkbox.common.scss # core/src/components/checkbox/checkbox.tsx # core/src/components/checkbox/checkbox.vars.scss # core/src/components/checkbox/test/basic/checkbox.e2e.ts # core/src/components/checkbox/test/basic/checkbox.e2e.ts-snapshots/checkbox-focus-ios-ltr-Mobile-Chrome-linux.png # core/src/components/checkbox/test/basic/checkbox.e2e.ts-snapshots/checkbox-focus-ios-ltr-Mobile-Firefox-linux.png # core/src/components/checkbox/test/basic/checkbox.e2e.ts-snapshots/checkbox-focus-ios-ltr-Mobile-Safari-linux.png # core/src/components/checkbox/test/basic/checkbox.e2e.ts-snapshots/checkbox-in-item-focus-ios-ltr-Mobile-Chrome-linux.png # core/src/components/checkbox/test/basic/checkbox.e2e.ts-snapshots/checkbox-in-item-focus-ios-ltr-Mobile-Safari-linux.png # core/src/components/fab-button/fab-button.tsx # core/src/components/item/test/buttons/item.e2e.ts-snapshots/item-buttons-diff-ios-ltr-Mobile-Chrome-linux.png # core/src/components/item/test/buttons/item.e2e.ts-snapshots/item-buttons-diff-ios-rtl-Mobile-Chrome-linux.png # core/src/components/item/test/colors/item.e2e.ts-snapshots/item-colors-diff-ios-ltr-Mobile-Chrome-linux.png # core/src/components/radio/radio.common.scss # core/src/components/radio/radio.ios.vars.scss # core/src/components/radio/radio.md.vars.scss # core/src/components/radio/radio.native.vars.scss # core/src/components/radio/test/basic/radio.e2e.ts # core/src/components/spinner/test/color/spinner.e2e.ts-snapshots/spinner-color-diff-md-ltr-Mobile-Firefox-linux.png # core/src/components/toggle/toggle.common.scss # core/src/components/toggle/toggle.tsx # core/src/components/toggle/toggle.vars.scss # packages/angular/src/directives/proxies.ts # packages/angular/standalone/src/directives/proxies.ts
The conflicting snapshots changed on main only from the playwright 1.62.1 bump, while next changed them from real component rendering work. Carry next's baselines forward; the checkbox focus snapshots stay on main's because #31295 is the code landing here.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ents The keyboard focus indicator is drawn 7px outside the control, so it widened the hit area and swallowed clicks aimed just past the control. A checkbox clicked below itself kept focus instead of blurring, so the next click emitted no ionFocus. This only surfaced on next: main starts the focus-visible utility in ion-app, so a setContent test without one never got ion-focused and never drew the ring. next initializes it globally (#31165), so the ring main added in #31295 now renders in those tests too. The indicator is decorative and must never take pointer events. The ios toggle uses box-shadow, which cannot capture them, so it needs no change.
The snapshot update run captured the md/Mobile Safari modal before the datetime calendar body rendered, so the regenerated baseline has an empty day grid. Restore next's baseline. The calendar is driven by an IntersectionObserver and the test only waits for ionModalDidPresent, so a loaded Linux WebKit shard can screenshot before the grid lands. Nothing in this merge touches datetime: the other five browser/mode baselines for the same test were unchanged, and the grid populates 15/15 locally on WebKit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sync next with main.